It would seem that it isn't as hard to patch the initial sequence number problem for TCP as it might seem. I might add, that this *ISN'T* a complete fix for the problem, but it will make it harder for people to perform attacks as described in Steve Bellovin's paper. Whilst swIPe is nice, it suffers from export restrictions (:-) and requires being setup at both ends to work. This patch should increase the difficulty level of someone taking over an arbitary connection to your host. First, let me point out that this patch won't solve *all* cases of TCP connections being guessable, (I don't think), and definately not the case described by this piece of code (from NetBSD): .... /* * If a new connection request is received * while in TIME_WAIT, drop the old connection * and start over if the sequence numbers * are above the previous ones. */ if (tiflags & TH_SYN && tp->t_state == TCPS_TIME_WAIT && SEQ_GT(ti->ti_seq, tp->rcv_nxt)) { iss = tp->rcv_nxt + TCP_ISSINCR; tp = tcp_close(tp); goto findpcb; } .... Here's a sample output from adb /vmunix /dev/kmem from a standard SunOS kernel: tcp_iss/ _tcp_iss: 880c200 = bleu f81873e8 tcp_iss/ _tcp_iss: _tcp_iss: 8869e00 = bleu f82fe3e8 tcp_iss/ _tcp_iss: _tcp_iss: 8879800 = bleu f833cbe8 tcp_iss/ _tcp_iss: _tcp_iss: 8889200 = bleu f837b3e8 tcp_iss/ _tcp_iss: _tcp_iss: 8898c00 = bleu f83b9be8 tcp_iss/ _tcp_iss: _tcp_iss: 88a8600 = bleu f83f83e8 tcp_iss/ _tcp_iss: _tcp_iss: 88a8600 = bleu f83f83e8 (tcp_iss is used to initialize the sequence/ack numbers). Proposed Solution: assign random numbers to tcp_iss. Problem: this approach *totally* flies in the face of RFC-793 (and RFC-1122) with regard to choice of the initial TCP sequence number, giving consideration to the MSL. Next Solution: increase rate of exhausting the sequence number window. The usual rate of increase is 125*1024 each second. If we assume the MSL to be 2 minutes (it is interesting to speculate about what the effect of flooding TCP over a high bandwidth will have here - high as in around 0.5 GB/s and above - as it is possible to exhaust the tcp sequence space through data) then we can increase the initial sequence number by a good deal more than the 250,000 per second. It would seem, that from reading through the code, that to maintain compatibility with (a bug ?) 4.2BSD, the initial sequence number is limited to 0 - 2147483647. If we choose to exhaust the sequence number space in less than the 4.55 hours (125*1024*3600*4.55 = 2096640000), then we can increment the tcp_iss faster. Incrementing the ISN by 4356761 every second will make it wrap in around 8 minutes. This is around 4 times the MSL, and I've seen connections hang around in various wait states for quite some time... hmmm... Something which both papers seem to have missed is that on reboot, the ISN is initialised to 1, every time! This can make the prediction of sequence numbers almost trivial. In the patch provided, there are two different ways of changing the ISN: increased speed of cycling through the window using a prime number to increment with and changing the ISN using the internal clock as a random number generator (no flames please, I know it's not that good). I'd recommend trying the first in preference to the second unless you know what you're doing and what to expect. The patch should be easily applied to any of the BSD based operating systems (Ultrix/SunOS/NetBSD/ FreeBSD/BSDI/BSD386) which require compiling /sys/netinet/in_proto.c to build a kernel. If you have the full source, you could do it properly and not need this abomination. Cheers, Darren *** /sys/netinet/in_proto.c.orig Fri Oct 14 06:45:48 1994 --- /sys/netinet/in_proto.c Tue Jan 24 17:49:16 1995 *************** *** 21,26 **** --- 21,27 ---- #include <netinet/in.h> #include <netinet/in_systm.h> #include <netinet/tcp_timer.h> + #include <netinet/tcp.h> /* * TCP/IP protocol family: IP, ICMP, UDP, TCP. *************** *** 35,40 **** --- 36,42 ---- int tcp_usrreq(),tcp_ctloutput(); int tcp_init(),tcp_fasttimo(),tcp_slowtimo(),tcp_drain(); int rip_input(),rip_output(),rip_ctloutput(); + int rand_tcp_slowtimer(), rand_tcp_fasttimo(), rand_tcp_init(); extern int raw_usrreq(); #ifdef NSIP *************** *** 57,63 **** { SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD, tcp_input, 0, tcp_ctlinput, tcp_ctloutput, tcp_usrreq, ! tcp_init, tcp_fasttimo, tcp_slowtimo, tcp_drain, }, { SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR, rip_input, rip_output, 0, rip_ctloutput, --- 59,65 ---- { SOCK_STREAM, &inetdomain, IPPROTO_TCP, PR_CONNREQUIRED|PR_WANTRCVD, tcp_input, 0, tcp_ctlinput, tcp_ctloutput, tcp_usrreq, ! rand_tcp_init, rand_tcp_fasttimo, rand_tcp_slowtimer, tcp_drain, }, { SOCK_RAW, &inetdomain, IPPROTO_RAW, PR_ATOMIC|PR_ADDR, rip_input, rip_output, 0, rip_ctloutput, *************** *** 148,150 **** --- 150,233 ---- int udp_sendspace = 9000; /* really max datagram size */ int udp_recvspace = 2*(9000+sizeof(struct sockaddr)); /* 2 8K dgrams */ + /* + * This is designed to introduce some randomness into the TCP sequence + * numbers. + * - Darren Reed 24/1/95 (avalon@coombs.anu.edu.au) + */ + extern tcp_seq tcp_iss; + + #define FASTER_ISN + #undef RANDOM_ISN + #ifndef TCP_COMPAT_42 + #define TCP_COMPAT_42 /* better defined than not */ + #endif + /* + * Make initial choice more random. + */ + rand_tcp_init() + { + int r = tcp_init(); + unsigned long ul[2]; + + uniqtime(ul); + tcp_iss = ul[0] * ul[1]; + if (tcp_iss < 0) + tcp_iss = -tcp_iss; + return r; + } + + + /* + * Get this 2 times a second (PR_SLOWHZ) + */ + rand_tcp_slowtimer() + { + int s = splnet(), r; + unsigned long ul[2]; + + r = tcp_slowtimo(); + /* + * we should still be at splnet() + */ + #ifdef RANDOM_ISN + uniqtime(ul); + if (!tcp_iss) + tcp_iss = ul[0] * 16381; /* prime multiplier */ + tcp_iss += ul[1]; + #else + # ifdef FASTER_ISN + tcp_iss += 4356761 / PR_SLOWHZ; /* prime / non prime */ + # endif + #endif + #ifdef TCP_COMPAT_42 + if (tcp_iss < 0) + tcp_iss = 1; + #endif + splx(s); + return r; + } + + + /* + * Get this 5 times a second (PR_FASTHZ) + */ + rand_tcp_fasttimo() + { + int s = splnet(), r; + + #ifdef RANDOM_ISN + tcp_iss *= 32749; /* prime multiplier */ + #else + # ifdef FASTER_ISN + tcp_iss += 149; /* prime addition */ + # endif + #endif + #ifdef TCP_COMPAT_42 + if (tcp_iss < 0) + tcp_iss = 1; + #endif + r = tcp_fasttimo(); + splx(s); + return r; + }